#include "mainwindow.h"
#include<QToolBar>
#include<QPushButton>
#include"toolgroup.h"
#include<QFileDialog>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/types_c.h>
#include<opencv2/ximgproc.hpp>
#include<queue>
#include<utility>
#include<QGridLayout>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QToolBar *toolBar=new QToolBar(this);
    addToolBar(Qt::BottomToolBarArea,toolBar);
    toolBar->setMovable(false);
    toolBar->setFloatable(false);

    QPushButton *openBtn=new QPushButton("打开图片",this);
    darkChanelRadius=new ToolGroup("暗通道腐蚀半径",0,40,1,15,0,this);
    tMin=new ToolGroup("透射率下界t_min",0.001,1,0.001,0.1,3,this);
    omega=new ToolGroup("去雾程度ω",0,1.5,0.001,0.95,3,this);
    guideRadius=new ToolGroup("导引滤波半径",0,299,1,15,0,this);
    guideEps=new ToolGroup("导引滤波正则因子ε",0,100000,0.001,0.1,3,this);

    darkChanelRadius->setEnabled(false);
    tMin->setEnabled(false);
    omega->setEnabled(false);
    guideRadius->setEnabled(false);
    guideEps->setEnabled(false);

    connect(darkChanelRadius,&ToolGroup::valueChanged,this,&MainWindow::updateImageSlot);
    connect(tMin,&ToolGroup::valueChanged,this,&MainWindow::updateImageSlot);
    connect(omega,&ToolGroup::valueChanged,this,&MainWindow::updateImageSlot);
    connect(guideRadius,&ToolGroup::valueChanged,this,&MainWindow::updateImageSlot);
    connect(guideEps,&ToolGroup::valueChanged,this,&MainWindow::updateImageSlot);
    connect(openBtn,&QPushButton::clicked,[&]{
        QString srcPath=QFileDialog::getOpenFileName(this,"打开图片","D:\\data",tr("Image Files (*.png *.jpg *.bmp *.jpeg)"));
        if(srcPath.isNull()) return;
        fogImg=cv::imread(srcPath.toLatin1().data());

        pg->removeWidget(beforeImg);
        pg->removeWidget(tHatImg);
        pg->removeWidget(imgarea);


        int maxLength=450;
        if(fogImg.rows>fogImg.cols){
            pg->addWidget(beforeImg,1,2,1,1);
            pg->addWidget(tHatImg,1,1,1,1);
            pg->addWidget(imgarea,1,3,1,1);
        }
        else{
            pg->addWidget(beforeImg,1,2,1,2);
            pg->addWidget(tHatImg,2,1,1,2);
            pg->addWidget(imgarea,2,3,1,2);
        }

        if(std::max(fogImg.rows,fogImg.cols)>maxLength){
            double scale=(double)maxLength/std::max(fogImg.rows,fogImg.cols);
            cv::resize(fogImg,fogImg,cv::Size(fogImg.cols*scale,fogImg.rows*scale));
        }
        cv::cvtColor(fogImg,fogImg,CV_BGR2RGB);
        beforeImg->setImg(fogImg);
        imgarea->setImg(calc(fogImg,15,0.1,0.95,15,0.1));
        darkChanelRadius->setEnabled(true);
        tMin->setEnabled(true);
        omega->setEnabled(true);
        guideRadius->setEnabled(true);
        guideEps->setEnabled(true);
    });

    toolBar->addWidget(openBtn);
    toolBar->addWidget(darkChanelRadius);
    toolBar->addWidget(tMin);
    toolBar->addWidget(omega);
    toolBar->addWidget(guideRadius);
    toolBar->addWidget(guideEps);

    beforeImg=new ImgArea();
    imgarea=new ImgArea();
    tHatImg=new ImgArea();

    pg=new QGridLayout(this);
    pg->setHorizontalSpacing(2);
    pg->addWidget(beforeImg,1,2,1,1);
    pg->addWidget(tHatImg,1,1,1,1);
    pg->addWidget(imgarea,1,3,1,1);
    QWidget *www=new QWidget();
    www->setLayout(pg);

    setCentralWidget(www);
    setWindowState(Qt::WindowMaximized);
}

MainWindow::~MainWindow(){
}

cv::Mat MainWindow::calc(cv::Mat& fog,int darkRadius,double tMin,double omega,int guideRadius,double guideEps){
    cv::Mat darkChannel(fog.rows,fog.cols,CV_8UC1);
    for(int i=0,r=fog.rows;i<r;i++){
        for(int j=0,c=fog.cols;j<c;j++){
            auto tmp=fog.at<cv::Vec3b>(i,j);
            darkChannel.at<uchar>(i,j)=std::min(std::min(tmp[0],tmp[1]),tmp[2]);
        }
    }
    cv::erode(darkChannel,darkChannel,getStructuringElement(cv::MORPH_RECT,cv::Size(darkRadius*2+1,darkRadius*2+1)));
    cv::Mat tHat;
    cv::ximgproc::guidedFilter(fog,darkChannel,tHat,guideRadius,guideEps);

    for(int i=0,r=fog.rows;i<r;i++){
        for(int j=0,c=fog.cols;j<c;j++){
            tHat.at<uchar>(i,j)=std::max(255.0-omega*tHat.at<uchar>(i,j),tMin*255);
        }
    }
    tHatImg->setImg(tHat);
    std::priority_queue<std::pair<uchar,std::pair<int,int>>> q;

    for(int i=0,r=fog.rows;i<r;i++){
        for(int j=0,c=fog.cols;j<c;j++){
            q.push(std::make_pair(darkChannel.at<uchar>(i,j),std::make_pair(i,j)));
            if(q.size()>r*c*0.001){
                q.pop();
            }
        }
    }
    double A=0;
    while(!q.empty()){
        auto pixel=fog.at<cv::Vec3b>(q.top().second.first,q.top().second.second);
        A=std::max((double)std::max(std::max(pixel[0],pixel[1]),pixel[2]),A);
        q.pop();
    }
    A/=255.0;
    qDebug()<<A;
    cv::Mat unfog(fog.rows,fog.cols,CV_8UC3);

    for(int i=0,r=fog.rows;i<r;i++){
        for(int j=0,c=fog.cols;j<c;j++){
            for(int k=0;k<3;k++){
                double before=fog.at<cv::Vec3b>(i,j)[k];
                before/=255.0;
                double t=tHat.at<uchar>(i,j);
                t/=255.0;
                unfog.at<cv::Vec3b>(i,j)[k]=std::max(std::min(255,int(255*((before-A)/t+A))),0);
            }
        }
    }
    return unfog;
}

void MainWindow::updateImageSlot(){
    int darkChangeRadius_=darkChanelRadius->getNum();
    double tMin_=tMin->getNum();
    double omega_=omega->getNum();
    int guideRadius_=guideRadius->getNum();
    double guideEps_=guideEps->getNum();
    imgarea->setImg(calc(fogImg,darkChangeRadius_,tMin_,omega_,guideRadius_,guideEps_));
}
